import logging
import time
from datetime import datetime

import redis

SEVERITY={
    logging.DEBUG:'debug',
    logging.INFO:'info',
    logging.WARNING:'warning',
    logging.ERROR:'debug',
    logging.CRITICAL:'critical',
}
SEVERITY.update((name,name) for name in SEVERITY.values())

def log_recent(conn,name,message,severity=logging.INFO,pipe=None):
    #尝试将日志的安全级别准还为简单的字符串
    severity=str(SEVERITY.get(severity,severity)).lower()
    #创建负责存储消息的键
    destination='recent:%s:%s'%(name,severity)
    #将当前时间添加到消息里面，用于记录消息的发送时间
    message=time.asctime()+'  '+message
    #使用流水线来将通信往返次数降低为一次
    pipe=pipe or conn.pipeline()
    #将消息添加到日志列表的最前面
    pipe.lpush(destination,message)
    #对日志列表进行修建，让它只包含最新的100条消息
    pipe.ltrim(destination,0,99)
    #执行两个命令
    pipe.execute()

def log_common(conn,name,message,severity=logging.INFO,timeout=5):
    # 尝试将日志的安全级别准还为简单的字符串
    severity = str(SEVERITY.get(severity, severity)).lower()
    #负责存储近期的常见日志消息的键
    destination = 'common:%s:%s' % (name, severity)
    #因为程序每小时需要轮换一次日志，所以它使用一个键来记录当前所处的小时数
    start_key=destination+':start'
    # 使用流水线来将通信往返次数降低为一次
    pipe = conn.pipeline()
    end=time.time()+timeout
    while time.time()<end:
        try:
            #当记录当前小时数的键进行监视，确保轮换操作可以正确的执行
            pipe.watch(start_key)
            #取得当前时间
            now=datetime.utcnow().timetuple()
            #取得当前所处的小时数
            hour_start=datetime(*now[:4].isoformat())

            existing=pipe.get(start_key)
            #创建一个事务
            pipe.multi()
            #如果这个常见日志消息列表记录的是上个小时的日志。。
            if existing and existing<hour_start:
                #将这些旧的常见日志消息归档
                pipe.rename(destination,destination+':last')
                pipe.rename(start_key,destination+':pstart')
                #更新当前所处的小时数
                pipe.set(start_key,hour_start)
            elif not existing:
                pipe.set(start_key,hour_start)
            #对记录日志出现次数的计数器执行自增操作
            pipe.zincrby(destination,message)
            #log_recent()函数负责记录日志并调用execute()函数
            log_recent(pipe,name,message,severity,pipe)
            return
        except redis.exceptions.WatchError:
            continue